package mn.more.foundation.lang;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * @author $Author: mikeliucc $
 * @version $Id: DateOperator.java 5 2008-09-01 12:08:42Z mikeliucc $
 */
public final class DateOperator {

	private DateOperator() { }

	public static void clearTimeFields(Calendar c) {
		c.set(Calendar.HOUR_OF_DAY, 0);
		c.set(Calendar.MINUTE, 0);
		c.set(Calendar.SECOND, 0);
		c.set(Calendar.MILLISECOND, 0);
	}

	public static void clearTimeFields(Date d) {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		clearTimeFields(c);
		d.setTime(c.getTime().getTime());
	}

	/**
	 * Construct a new date by rolling a field of a (relative) <code>date</code>
	 * forwards or backwards by <code>amount</code>.
	 */
	private static Date increment(Date date, int field, int amount) {
		Calendar calendar = new GregorianCalendar();
		calendar.setTime(date);
		calendar.add(field, amount);
		return calendar.getTime();
	}

	/**
	 * Contstruct a new date by rolling a field of a (relative) <code>date</code>
	 * forwards or backwards.
	 */
	private static Date increment(Date date, int field, boolean up) {
		return increment(date, field, (up ? 1 : -1));
	}

	public static Date previousMonth(Date date) {
		return increment(date, Calendar.MONTH, false);
	}

	public static Date previousYear(Date date) {
		return increment(date, Calendar.YEAR, false);
	}

	public static Date nextMonth(Date date) {
		return increment(date, Calendar.MONTH, true);
	}

	public static Date nextYear(Date date) {
		return increment(date, Calendar.YEAR, true);
	}

	public static Date addMillisecond(Date date, int millis) {
		return increment(date, Calendar.MILLISECOND, millis);
	}

	public static Date addSecond(Date date, int seconds) {
		return increment(date, Calendar.SECOND, seconds);
	}

	public static Date addMinute(Date date, int minutes) {
		return increment(date, Calendar.MINUTE, minutes);
	}

	public static Date addHour(Date date, int hours) {
		return increment(date, Calendar.HOUR_OF_DAY, hours);
	}

	public static Date addDay(Date date, int days) {
		return increment(date, Calendar.DAY_OF_MONTH, days);
	}

	public static Date addMonth(Date date, int months) {
		return increment(date, Calendar.MONTH, months);
	}

	public static Date addYear(Date date, int years) {
		return increment(date, Calendar.YEAR, years);
	}

	/**
	 * This method returns a Date object that is the first date for the current
	 * month. For example: If today's date is 07/22/2001, the method returns a Date
	 * 07/01/2001
	 *
	 * @return java.util.Date
	 */
	public static Date firstOfCurrentMonth() {
		return firstOfMonth(new Date());
	}

	/**
	 * This method returns a Date object that is the first date for the current
	 * month. For example: If today's date is 07/22/2001, the method returns a Date
	 * 07/01/2001
	 *
	 * @return java.util.Date
	 */
	public static Date firstOfMonth(Date myDate) {
		if (myDate == null) { return null; }
		Calendar thisDay = new GregorianCalendar();
		thisDay.setTime(myDate);
		thisDay.set(Calendar.DAY_OF_MONTH,
		            thisDay.getActualMinimum(Calendar.DAY_OF_MONTH));
		return thisDay.getTime();
	}

	/**
	 * This method returns a Date object that is the last date for the current
	 * month. For example: If today's date is 07/22/2001, the method returns a Date
	 * 07/31/2001
	 *
	 * @return java.util.Date
	 */
	public static Date lastOfCurrentMonth() { return lastOfMonth(new Date()); }

	/**
	 * This method returns a Date object that is the last date for the current
	 * month. For example: If today's date is 07/22/2001, the method returns a Date
	 * 07/31/2001
	 *
	 * @return java.util.Date
	 */
	public static Date lastOfMonth(Date myDate) {
		if (myDate == null) { return null; }
		GregorianCalendar thisDay = new GregorianCalendar();
		thisDay.setTime(myDate);
		thisDay.set(Calendar.DAY_OF_MONTH,
		            thisDay.getActualMaximum(Calendar.DAY_OF_MONTH));
		return thisDay.getTime();
	}

	/**
	 * get the Sunday closest to today
	 *
	 * @return java.util.Date
	 */
	public static Date currentSunday() {
		// get current date
		Calendar today = new GregorianCalendar();

		// find the most current Sunday
		today.add(Calendar.DATE, (today.get(Calendar.DAY_OF_WEEK) - 1) * -1);

		// return value as a Date object
		return today.getTime();
	}

	/**
	 * get the next Sunday coming up
	 *
	 * @return java.util.Date
	 */
	public static Date nextSunday() {
		// get current date
		Calendar today = Calendar.getInstance();

		// find the next Sunday
		today.add(Calendar.DATE, (7 - today.get(Calendar.DAY_OF_WEEK) + 1));

		// return value as a Date object
		return today.getTime();
	}

	/**
	 * get the Sunday just passed
	 *
	 * @return java.util.Date
	 */
	public static Date previousSunday() {
		// get current date
		Calendar today = Calendar.getInstance();

		// find the previous Sunday
		today.add(Calendar.DATE, (today.get(Calendar.DAY_OF_WEEK) + 6) * -1);

		// return value as a Date object
		return today.getTime();
	}
}
